class Texture;

enum TexCreateType {TXCT_NORMALIZATION_CUBE_MAP = 1};

enum TextureBlend {TB_REPLACE = 0
	,TB_MULTIPLY	= 1
	,TB_ADD			= 2
	,TB_DECAL		= 3
	,TB_ALPHA		= 4
	,TB_DOT3		= 5
	,TB_SUBSTRACT	= 6
	,TB_OVERLAY		= 7
};

class TexSize
{
public:
	int width;
	int height;
	TexSize(int width,int height);
	TexSize(int size);
	TexSize();
};

namespace TexFilesManager
{
	class GLTexUse
	{
	public:
		Texture *tid;
		unsigned int links;
	};

	typedef std::map<std::string,GLTexUse> Ttexfilesmap;
	Ttexfilesmap texfilesmap;

	void AddTexture(const char *filename,Texture *tex);
	void RemoveTexture(Texture *tex);
	Texture* AlreadyLoaded(const char *filename);
}

namespace TextureSharedData
{
	GLuint gltexID;
	unsigned int CurrentTexMode;
}

const unsigned int CNT_TEXUNITS=32;

const int TEX_2D=0;
const int TEX_3D=1;

const int TM_AUTO = 0;
const int TM_1D=1;
const int TM_2D=2;
const int TM_3D=4;
const int TM_RECT=8;
const int TM_CUBEMAP=128;


const int TE_NONE=0x01;
const int TE_ALPHA=0x02;
const int TE_MUL=0x03;
const int TE_ADD=0x04;
const int TE_COLOR=0x05;

const unsigned int TF_COLOR = 1;
const unsigned int TF_ALPHA = 2;
const unsigned int TF_MASKED = 4;
const unsigned int TF_MIPMAP = 8;
const unsigned int TF_CLAMP = 16;
const unsigned int TF_ANISOTROPIC = 32;
const unsigned int TF_SPHEREMAP = 64;
const unsigned int TF_CUBEMAP = 128;
const unsigned int TF_NORMALCUBE = 512;
const unsigned int TF_NO_COMPRESSING = 1024;

class Texture
{
	GLuint handle;
	unsigned int texmode;
	unsigned int texmodeGL;
	unsigned int texenv;
	unsigned int texenvGL;
	unsigned int min_filter;
	unsigned int mag_filter;
	bool spheremap,cubemap,normalcube;
	GLfloat anisotropic;
	void UpdateFlags();
	void ApplyParams();
	unsigned int flags;
	image_src *src;
	void Build();

	unsigned int twidth;
	unsigned int theight;
	unsigned int tdepth;
	unsigned int tbpp;
	unsigned int ttype;
	int tbpc;

	int currentlayer;

	void createnormalizationcube(int size);
	unsigned int use_combiner;

public:
	Texture(const char* filename,unsigned int flags,unsigned int texenv,unsigned int filter,unsigned int texmode);
	Texture(const image_src* source,unsigned int flags,unsigned int texenv,unsigned int filter,unsigned int texmode);
	Texture(TexSize size,int bpp_,int txmode, int format, int bpc);
	Texture(const char **fnames,unsigned int flags,unsigned int texenv,unsigned int filter,unsigned int texmode);
	Texture(unsigned int resourceID,unsigned int flags,unsigned int texenv,unsigned int filter,unsigned int texmode);
	Texture(TexCreateType tp,int param0,int param1,int param2);

	~Texture();
	void Bind(void);
	void Bind(unsigned int layer);
	void Blend(TextureBlend tb);
	void UnBind(void);
	void SoftUnBind(void);
	int Texture::SetAnisotropyLevel(float level);
	float Texture::GetAnisotropyLevel();
	void SetFlag(unsigned int flag_);
	void DropFlag(unsigned int flag_);
	void SetAFL(float AnisotropyLevel);
	void SetParametr(GLenum param,int value);
	void SetParametr(GLenum param,float value);
	void Grab();
	void GrabDepth();
	void Restore();
	image_src* GetImage();
	void SetImage(image_src *img);
	void SetTexBlend(unsigned int mode);
	void Show(int x,int y,int width,int height,int layer);
	void Show(int x,int y,int layer);
	void InvShow(int x,int y,int width,int height,int layer);
	void InvShow(int x,int y,int layer);

	void SetFilter(int filter);
	int Save(const char *filename);

	GLuint GetGLTexture(){return handle;}

	int GetWidth();
	int GetHeight();
	int GetDepth();
	int GetBPP();
	int GetBPC();

	unsigned int GetGLTextType();

	void Wrap(unsigned int method);
};

Texture **cur_bind_tex = 0;
bool texturing;

namespace other_tex_formats
{
#ifdef SIGEL_SYSTEM_DEVIL
	ILboolean vxm_loadfunc ( const char * fileName );
	ILboolean vxm_savefunc ( const char * fileName );
#endif
}

Texture *CreateNormalizationCubeMap(int size)
{
	DEBUG_LOG("CreateNormalizationCubeMap");
	Texture *result = new Texture(TXCT_NORMALIZATION_CUBE_MAP,size,0,0);
	result->Blend(TB_DOT3);

	return result;
}
